/**
 * A collection of mathematical functions not offered by the
 * standard class Math in the Java API.
 * 
 * @version  2.0
 * @author   Eric Steegmans, edited by Inge Gielis & Gerlinde Van Roey
 */
public class ExtMath {

	/**
	 * Check whether the given floating point numbers can be added.
	 *
	 * @param   a
	 *          The first floating point number to be checked.
	 * @param   b
	 *          The other floating point number to be checked.
	 * @return  If the given floating point numbers are both positive,
	 *          true if and only if a does not exceed the largest
	 *          possible value in the type double diminished with b.
	 *        | if ( (a > 0) && (b > 0) )
	 *        |   then result == (a <= Double.MAX_VALUE - b)
	 * @return  If the given floating point numbers are both negative,
	 *          true if and only if a is not below the smallest
	 *          possible value in the type double diminished with b.
	 *        | if ( (a < 0) && (b < 0) )
	 *        |   then result == (a >= Double.MIN_VALUE - b)
	 * @return  If the given floating point numbers have different signs
	 *          always true.
	 *        | if ( ( (a <= 0) && (b >= 0) )
	 *        |   || ( (a >= 0) && (b <= 0) ) )
	 *        |   then result == true
	 */
	public static boolean areAddable(double a, double b) {
		if ((a > 0) && (b > 0))
			return a <= Double.MAX_VALUE - b;
		if ((a < 0) && (b < 0))
			return a >= Double.MIN_VALUE - b;
		return true;
	}

	/**
	 * Return the sum of the given floating point numbers.
	 * 
	 * @param   a
	 *          The left operand for the addition.
	 * @param   b
	 *          The right operand for the addition.
	 * @return  The sum of the given numbers.
	 *        | result == a + b
	 * @throws  AddOverflowException
	 *          The given floating point numbers cannot be added.
	 *        | ! areAddable(a,b)
	 */
	public static double add(double a, double b) throws AddOverflowException {
		if (!areAddable(a, b))
			throw new AddOverflowException(a, b);
		return a + b;
	}

	/**
	 * Check whether the given floating point numbers can be multiplied.
	 *
	 * @param   a
	 *          The first floating point number to be checked.
	 * @param   b
	 *          The other floating point number to be checked.
	 * @return  If the given floating point numbers have the same sign,
	 *          true if and only if the absolute value of a does
	 *          not exceed the largest possible value in the type
	 *          double divided by the absolute value of b.
	 *        | if ( ( (a > 0) && (b > 0) )
	 *        |   || ( (a < 0) && (b < 0) ) )
	 *        | then
	 *        |   result == 
	 *        |     (Math.abs(a) <= Double.MAX_VALUE / Math.abs(b))
	 * @return  If a is positive and b is negative, true if and
	 *          only if b is not below the smallest possible value
	 *          in the type double divided by a.
	 *        | if ( (a > 0) && (b < 0) )
	 *        |   then result == (b >= Double.MIN_VALUE / a)
	 * @return  If b is positive and a is negative, true if and
	 *          only if a is not below the smallest possible value
	 *          in the type double divided by b.
	 *        | if ( (a < 0) && (b > 0) )
	 *        |   then result == (a >= Double.MIN_VALUE / b)
	 * @return  If a is zero or if b is zero, always true.
	 *        | if ( (a == 0) || (b == 0) )
	 *        |   then result == true
	 */
	public static boolean areMultipliable(double a, double b) {
		if (((a > 0) && (b > 0)) || ((a < 0) && (b < 0)))
			return (Math.abs(a) <= Double.MAX_VALUE / Math.abs(b));
		if ((a < 0) && (b > 0))
			return (a >= Double.MIN_VALUE / b);
		if ((a > 0) && (b < 0))
			return (b >= Double.MIN_VALUE / a);
		return true; // a or b is 0
	}

	/**
	 * Return the product of the given floating point numbers.
	 * 
	 * @param   a
	 *          The left operand for the product.
	 * @param   b
	 *          The right operand for the product.
	 * @return  The product of the given numbers.
	 *        | result == a * b
	 * @throws  TimesOverflowException
	 *          The given floating point numbers cannot be multiplied.
	 *        | ! areMultipliable(a,b)
	 */
	public static double times(double a, double b) throws TimesOverflowException {
		if (!areMultipliable(a, b))
			throw new TimesOverflowException(a, b);
		return a * b;
	}

}